<template>
  <div class="mall-map-container">
    <div class="mask" @click="moveLineRestart"></div>
    <div class="map-groups">
      <img :src="mallMapBg" alt="map-bg" class="map-bg" ref="domMapBg">
      <div class="map-canvas" ref="domMapCanvas" :style="{width: ((480 * scale.w) / scale.h) + 'px'}"></div>
    </div>
  </div>
</template>

<script type="text/ecmascript-6">
import { mapGetters } from 'vuex'
/**
 * A lightweight canvas library which providing 2d draw for ECharts
 * @Documents https://github.com/ecomfe/zrender
 */
import Zrender from 'echarts/node_modules/zrender'
/**
 * 计算二阶贝塞尔曲线的控制点
 */
function calControlPoint (sx, sy, dx, dy) {
  let a, X, Y, len
  X = (sx + dx) / 2
  Y = (sy + dy) / 2
  len = 0.2 * Math.sqrt(Math.pow((dy - sy), 2) + Math.pow((dx - sx), 2))
  a = Math.atan2(dy - sy, dx - sx)
  a = 0.4
  return { x: X - len * Math.sin(a), y: Y + len * Math.cos(a) }
}

export default {
  name: 'mall-map',
  props: {
    ad: {
      type: Array,
      default: function () {
        return []
      }
    },
    adk: {
      type: Object,
      default: function () {
        return {}
      }
    },
    scale: {
      type: Object,
      default: function () {
        return {
          w: 100,
          h: 100
        }
      }
    },
    type: {
      type: String,
      default: 'moveLine'
    },
    isInit: {
      type: Boolean,
      default: false
    },
    data: [Array, Object]
  },

  created () {
    if (this.isInit) {
      this.$nextTick(() => {
        this.init()
      })
    }
  },

  beforeDestroy () {
    clearInterval(this.timerBallMove)
  },

  data () {
    return {
      currMovePathInx: 0
    }
  },

  computed: {
    ...mapGetters([
      'mallMapBg'
    ]),
    movePathData () {
      let data = []
      if (this.data.length === 0) {
        return data
      }
      if (this.data.length === 1) {
        const from = this.data[0]['zone_id']
        const to = this.data[0]['zone_id']
        const fp = this.adk[from].center.map(item => item * this.computedScale)
        const tp = this.adk[to].center.map(item => item * this.computedScale)
        const cp = [calControlPoint(fp[0], fp[1], tp[0], tp[1]).x, calControlPoint(fp[0], fp[1], tp[0], tp[1]).y]
        data.push({ fp, tp, cp, from, to })
        return data
      }
      for (let inx = 0; inx < this.data.length - 1; inx++) {
        const from = this.data[inx]['zone_id']
        const to = this.data[inx + 1]['zone_id']
        const fp = this.adk[from].center.map(item => item * this.computedScale)
        const tp = this.adk[to].center.map(item => item * this.computedScale)
        const cp = [calControlPoint(fp[0], fp[1], tp[0], tp[1]).x, calControlPoint(fp[0], fp[1], tp[0], tp[1]).y]
        data.push({ fp, tp, cp, from, to })
      }
      return data
    },
    computedScale () {
      return Math.round((this.$refs.domMapBg.offsetWidth / this.scale.w) * 100) / 100
    }
  },

  watch: {
    data (newv) {
      switch (this.type) {
        case 'moveLine':
          this.moveLineStart()
          break
        case 'heatmap':
          if (this.isInit) {
            this.heatMap()
          }
          break
        default:
          throw new Error('map type error')
      }
    },
    isInit (newv) {
      if (newv) {
        this.$nextTick(() => {
          this.init()
          this.addShape(this.mapCanvas, this.ad, this.computedScale)
        })
      } else {
        this.mapCanvas.dispose()
      }
    }
  },

  methods: {
    /**
     * 生成map canvas
     */
    init () {
      const domMapCanvas = this.$refs.domMapCanvas
      this.mapCanvas = Zrender.init(domMapCanvas)
    },
    /**
     * 添加色块
     * @param{Object => dom}dom    dom
     * @param{Array}ad    区域地理位置数据
     * @param{Number}scale    缩放比例
     */
    addShape (dom, ad, scale = 1) {
      for (let i = ad.length - 1; i >= 0; i--) {
        const points = ad[i].points.map((item) => {
          return item.map((point) => {
            return point * scale
          })
        })
        let key = `_canvasShape${ad[i].id}`
        this[key] = new Zrender.Polygon({
          shape: {
            points: points
          },
          style: {
            fill: 'rgba(0, 0, 0, .1)',
            text: ad[i].name,
            textFill: '#FFF',
            textPosition: [10, 10]
          }
        })
        dom.add(this[key])
      }
    },
    heatMap () {
      for (let i = this.ad.length - 1; i >= 0; i--) {
        let key = `_canvasShape${this.ad[i].id}`
        this[key].attr('style', {
          fill: this.data[this.ad[i].id] ? this.data[this.ad[i].id]['color'] : 'rgba(0, 0, 0, .1)',
          text: `${this.ad[i].name}${this.data[this.ad[i].id] ? ': ' + this.data[this.ad[i].id]['customer_num'] + '人' : ''}`
        })
      }
    },
    moveLineStart () {
      if (this.movePathData.length === 0) {
        return false
      }
      clearInterval(this.timerBallMove)
      this.mapCanvas.clear()
      this.len = 0
      this.currMovePathInx = 0
      // 计算
      this.addShape(this.mapCanvas, this.ad, this.computedScale)
      this.addPoint(this.mapCanvas, this.movePathData, this.computedScale)
      this.addLine(this.mapCanvas, this.adk, this.computedScale)
      this.addBall(this.mapCanvas, this.adk, this.computedScale)
      this.path = document.createElementNS('http://www.w3.org/2000/svg', 'path')
      this.timerBallMove = setInterval(() => {
        const x1 = this.movePathData[this.currMovePathInx].fp[0]
        const y1 = this.movePathData[this.currMovePathInx].fp[1]
        const cx = this.movePathData[this.currMovePathInx].cp[0]
        const cy = this.movePathData[this.currMovePathInx].cp[1]
        const x2 = this.movePathData[this.currMovePathInx].tp[0]
        const y2 = this.movePathData[this.currMovePathInx].tp[1]
        this.path.setAttribute('d', 'M' + x1 + ' ' + y1 + ' ' + 'Q' + cx + ' ' + cy + ' ' + x2 + ' ' + y2)
        this.currPathLen = this.path.getTotalLength()
        this.len = this.len === null || this.len === undefined ? 0 : this.len += 2
        let point = this.path.getPointAtLength(this.len)
        this.moveBall(point.x, point.y)
        if (this.len > this.currPathLen) {
          this.len = 0
          if (this.currMovePathInx >= this.movePathData.length - 1) {
            clearInterval(this.timerBallMove)
            return false
          }
          this.currMovePathInx++
        }
      }, 20)
    },
    moveLineRestart () {
      this.moveBall(this.movePathData[this.currMovePathInx].fp[0], this.movePathData[this.currMovePathInx].fp[1])
      this.moveLineStart()
    },
    addLine (dom, adk, scale = 1) {
      for (let inx = 0; inx < this.movePathData.length; inx++) {
        const path = this.movePathData[inx]
        const line = new Zrender.BezierCurve({
          shape: {
            x1: path.fp[0],
            y1: path.fp[1],
            x2: path.tp[0],
            y2: path.tp[1],
            cpx1: path.cp[0],
            cpy1: path.cp[1]
          },
          style: {
            stroke: 'rgba(87, 178, 224, .2)',
            lineWidth: 4
          }
        })
        dom.add(line)
      }
    },
    addBall (dom, adk, scale = 1) {
      const fillColor = new Zrender.RadialGradient(0.5, 0.5, 0.5, [{
        offset: 0,
        color: 'rgba(87, 178, 224, 1)'
      }, {
        offset: 1,
        color: 'rgba(87, 178, 224, 0)'
      }])
      this.ball = new Zrender.Circle({
        shape: {
          // points: points
          cx: this.movePathData[this.currMovePathInx].fp[0],
          cy: this.movePathData[this.currMovePathInx].fp[1],
          r: 8
        },
        style: {
          fill: fillColor
        }
      })
      dom.add(this.ball)
    },
    moveBall (x, y) {
      this.ball.attr('shape', {
        cx: x,
        cy: y,
        r: 10
      })
    },
    addPoint (dom, movePathData, scale = 1) {
      let stack = []
      for (let inx = 0; inx < movePathData.length; inx++) {
        const point = movePathData[inx]
        if (stack.find((n) => n === point.from) !== undefined) {
          continue
        }
        const fillColor = new Zrender.RadialGradient(0.5, 0.5, 0.5, [{
          offset: 0,
          color: 'rgba(61, 197, 208, 1)'
        }, {
          offset: 1,
          color: 'rgba(61, 197, 208, 0)'
        }])
        const circle = new Zrender.Circle({
          shape: {
            // points: points
            cx: point.fp[0],
            cy: point.fp[1],
            r: 8
          },
          style: {
            fill: fillColor
          }
        })
        dom.add(circle)
        stack.push(point.from)
      }
    }
  }
}
</script>

<style lang="less" rel="stylesheet/less" scoped>
  .mall-map-container {
    position: relative;
    width: 100%;
    height: 100%;
    height: 480px;
    // padding: 0 0 50px;
    background-color: #171c37;
    .mask {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      z-index: 1;
      cursor: pointer;
    }
    .map-groups {
      position: absolute;
      top: 0;
      left: 0;
      width: 100%;
      height: 100%;
      .map-bg {
        position: absolute;
        top: 0;
        left: 50%;
        transform: translateX(-50%);
        // TODO: media 媒体查询控制大小, 监听onresize事件
        width: auto;
        height: 480px;
      }
      .map-canvas {
        position: absolute;
        top: 0;
        left: 50%;
        transform: translateX(-50%);
        // TODO: media 媒体查询控制大小, 监听onresize事件
        // width: 1046.31px;
        height: 480px;
      }
    }
  }
</style>
